package com.lambkit.plugin.liteflow;

import cn.hutool.core.util.StrUtil;
import com.lambkit.core.Lambkit;
import com.lambkit.core.LifecycleState;
import com.lambkit.core.plugin.Plugin;
import com.lambkit.core.service.ScanClassProcess;
import com.lambkit.db.DbConfig;
import com.lambkit.db.DbPool;
import com.yomahub.liteflow.builder.LiteFlowNodeBuilder;
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.core.FlowExecutorHolder;
import com.yomahub.liteflow.property.LiteflowConfig;

import java.util.HashMap;
import java.util.Map;

/**
 * @author yangyong(孤竹行)
 */
public class LiteFlowPlugin extends Plugin {

    private LiteflowConfig config;
    private String packageScan = "com.lambkit";

    public LiteFlowPlugin() {
        config = new LiteflowConfig();
        String prefix = "lambkit.liteflow.";
        String type = Lambkit.config(prefix + "type", "default");
        if("sql".equals(type)) {
            Map<String, String> props = new HashMap<>();
            String configName = Lambkit.config(prefix + "configName", DbPool.DEFAULT_NAME);
            DbConfig dataSourceConfig = DbPool.config(configName);
            if(dataSourceConfig != null) {
                props.put("url", dataSourceConfig.getUrl());
                //System.out.println("url:" + dataSourceConfig.getUrl());
                props.put("driverClassName", dataSourceConfig.getDriverClassName());
                //System.out.println("driverClassName:" + dataSourceConfig.getDriverClassName());
                props.put("username", dataSourceConfig.getUser());
                //System.out.println("username:" + dataSourceConfig.getUser());
                props.put("password", dataSourceConfig.getPassword());
                //System.out.println("password:" + dataSourceConfig.getPassword());
            } else {
                props.put("url", Lambkit.config(prefix + "url", ""));
                props.put("driverClassName", Lambkit.config(prefix + "driverClassName", ""));
                props.put("username", Lambkit.config(prefix + "username", ""));
                props.put("password", Lambkit.config(prefix + "password", ""));
            }
            //是否开启SQL日志
            props.put("sqlLogEnabled", Lambkit.config(prefix + "sqlLogEnabled", "true"));
            //是否开启SQL数据轮询自动刷新机制 默认不开启
            props.put("pollingEnabled", Lambkit.config(prefix + "pollingEnabled", "true"));
            props.put("pollingIntervalSeconds", Lambkit.config(prefix + "pollingIntervalSeconds", "60"));
            props.put("pollingStartSeconds", Lambkit.config(prefix + "pollingStartSeconds", "60"));
            //以下是chain表的配置，这个一定得有
            props.put("chainTableName", Lambkit.config(prefix + "chainTableName", "bpms_rule_chain"));
            props.put("chainApplicationNameField", Lambkit.config(prefix + "chainApplicationNameField", "application_name"));
            props.put("chainNameField", Lambkit.config(prefix + "chainNameField", "chain_name"));
            props.put("elDataField", Lambkit.config(prefix + "elDataField", "el_data"));
            props.put("chainEnableField", Lambkit.config(prefix + "chainEnableField", "status"));
            //以下是script表的配置，如果你没使用到脚本，下面可以不配置
            props.put("scriptTableName", Lambkit.config(prefix + "scriptTableName", "bpms_rule_script"));
            props.put("scriptApplicationNameField", Lambkit.config(prefix + "scriptApplicationNameField", "application_name"));
            props.put("scriptIdField", Lambkit.config(prefix + "scriptIdField", "script_id"));
            props.put("scriptNameField", Lambkit.config(prefix + "scriptNameField", "script_name"));
            props.put("scriptDataField", Lambkit.config(prefix + "scriptDataField", "script_data"));
            props.put("scriptTypeField", Lambkit.config(prefix + "scriptTypeField", "script_type"));
            props.put("scriptLanguageField", Lambkit.config(prefix + "scriptLanguageField", "script_language"));
            props.put("scriptEnableField", Lambkit.config(prefix + "scriptEnableField", "status"));
            //自定义应用名称
            props.put("applicationName", Lambkit.config(prefix + "applicationName", "lambkit"));
            config.setRuleSourceExtDataMap(props);
        } else {
            String ruleSource = Lambkit.config(prefix + "ruleSource", "config/flow.el.xml");
            config.setRuleSource(ruleSource);
        }
        this.packageScan = Lambkit.config("packageScan", this.packageScan);
    }

    public LiteFlowPlugin(LiteflowConfig config, String packageScan) {
        this.config = config;
        this.packageScan = packageScan;
    }

    @Override
    public void start() {
        // 扫码并构造node节点
        if(StrUtil.isNotBlank(packageScan)) {
            Lambkit.context().classOperateService().scanPackageByAnnotation(packageScan, LiteFlowNode.class, new ScanClassProcess() {
                @Override
                public void process(Class<?> clazz) {
                    //System.out.println("clazz:"+clazz.getName());
                    LiteFlowNode liteFlowNode = clazz.getAnnotation(LiteFlowNode.class);
                    if (liteFlowNode == null || liteFlowNode.id() == null) {
                        return;
                    }
                    if("common".equalsIgnoreCase(liteFlowNode.type())) {
                        //构建一个普通组件
                        LiteFlowNodeBuilder.createCommonNode().setId(liteFlowNode.id())
                                .setName(liteFlowNode.name())
                                .setClazz(clazz)
                                .build();
                    } else if("switch".equalsIgnoreCase(liteFlowNode.type())) {
                        LiteFlowNodeBuilder.createSwitchNode().setId(liteFlowNode.id())
                                .setName(liteFlowNode.name())
                                .setClazz(clazz)
                                .build();
                    } else if("boolean".equalsIgnoreCase(liteFlowNode.type())) {
                        LiteFlowNodeBuilder.createBooleanNode().setId(liteFlowNode.id())
                                .setName(liteFlowNode.name())
                                .setClazz(clazz)
                                .build();
                    } else if("for".equalsIgnoreCase(liteFlowNode.type())) {
                        LiteFlowNodeBuilder.createForNode().setId(liteFlowNode.id())
                                .setName(liteFlowNode.name())
                                .setClazz(clazz)
                                .build();
                    } else if("iterator".equalsIgnoreCase(liteFlowNode.type())) {
                        LiteFlowNodeBuilder.createIteratorNode().setId(liteFlowNode.id())
                                .setName(liteFlowNode.name())
                                .setClazz(clazz)
                                .build();
                    }
                }
            });
        }
        FlowExecutor flowExecutor = FlowExecutorHolder.loadInstance(config);
        Lambkit.context().getBeanFactory().set(FlowExecutor.class, flowExecutor);
        //LiteFlowKit.setFlowExecutor(flowExecutor);
        setCurrentState(LifecycleState.STARTED);
    }

    public String getPackageScan() {
        return packageScan;
    }

    public void setPackageScan(String packageScan) {
        this.packageScan = packageScan;
    }
}
